Make GSettingsSchemaKey public
[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_WITH_PRIVATE (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   gobject_class = G_OBJECT_CLASS (klass);
100   gobject_class->finalize = _g_dbus_auth_mechanism_external_finalize;
101
102   mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
103   mechanism_class->get_name                  = mechanism_get_name;
104   mechanism_class->get_priority              = mechanism_get_priority;
105   mechanism_class->is_supported              = mechanism_is_supported;
106   mechanism_class->encode_data               = mechanism_encode_data;
107   mechanism_class->decode_data               = mechanism_decode_data;
108   mechanism_class->server_get_state          = mechanism_server_get_state;
109   mechanism_class->server_initiate           = mechanism_server_initiate;
110   mechanism_class->server_data_receive       = mechanism_server_data_receive;
111   mechanism_class->server_data_send          = mechanism_server_data_send;
112   mechanism_class->server_get_reject_reason  = mechanism_server_get_reject_reason;
113   mechanism_class->server_shutdown           = mechanism_server_shutdown;
114   mechanism_class->client_get_state          = mechanism_client_get_state;
115   mechanism_class->client_initiate           = mechanism_client_initiate;
116   mechanism_class->client_data_receive       = mechanism_client_data_receive;
117   mechanism_class->client_data_send          = mechanism_client_data_send;
118   mechanism_class->client_shutdown           = mechanism_client_shutdown;
119 }
120
121 static void
122 _g_dbus_auth_mechanism_external_init (GDBusAuthMechanismExternal *mechanism)
123 {
124   mechanism->priv = _g_dbus_auth_mechanism_external_get_instance_private (mechanism);
125 }
126
127 /* ---------------------------------------------------------------------------------------------------- */
128
129 static gboolean
130 mechanism_is_supported (GDBusAuthMechanism *mechanism)
131 {
132   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), FALSE);
133   /* This mechanism is only available if credentials has been exchanged */
134   if (_g_dbus_auth_mechanism_get_credentials (mechanism) != NULL)
135     return TRUE;
136   else
137     return FALSE;
138 }
139
140 static gint
141 mechanism_get_priority (void)
142 {
143   /* We prefer EXTERNAL to most other mechanism (DBUS_COOKIE_SHA1 and ANONYMOUS) */
144   return 100;
145 }
146
147 static const gchar *
148 mechanism_get_name (void)
149 {
150   return "EXTERNAL";
151 }
152
153 static gchar *
154 mechanism_encode_data (GDBusAuthMechanism   *mechanism,
155                        const gchar          *data,
156                        gsize                 data_len,
157                        gsize                *out_data_len)
158 {
159   return NULL;
160 }
161
162
163 static gchar *
164 mechanism_decode_data (GDBusAuthMechanism   *mechanism,
165                        const gchar          *data,
166                        gsize                 data_len,
167                        gsize                *out_data_len)
168 {
169   return NULL;
170 }
171
172 /* ---------------------------------------------------------------------------------------------------- */
173
174 static GDBusAuthMechanismState
175 mechanism_server_get_state (GDBusAuthMechanism   *mechanism)
176 {
177   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
178
179   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
180   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
181
182   return m->priv->state;
183 }
184
185 static gboolean
186 data_matches_credentials (const gchar *data,
187                           GCredentials *credentials)
188 {
189   gboolean match;
190
191   match = FALSE;
192
193   if (credentials == NULL)
194     goto out;
195
196   if (data == NULL || strlen (data) == 0)
197     goto out;
198
199 #if defined(G_OS_UNIX)
200   {
201     gint64 alleged_uid;
202     gchar *endp;
203
204     /* on UNIX, this is the uid as a string in base 10 */
205     alleged_uid = g_ascii_strtoll (data, &endp, 10);
206     if (*endp == '\0')
207       {
208         if (g_credentials_get_unix_user (credentials, NULL) == alleged_uid)
209           {
210             match = TRUE;
211           }
212       }
213   }
214 #else
215   /* TODO: Dont know how to compare credentials on this OS. Please implement. */
216 #endif
217
218  out:
219   return match;
220 }
221
222 static void
223 mechanism_server_initiate (GDBusAuthMechanism   *mechanism,
224                            const gchar          *initial_response,
225                            gsize                 initial_response_len)
226 {
227   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
228
229   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
230   g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
231
232   m->priv->is_server = TRUE;
233
234   if (initial_response != NULL)
235     {
236       if (data_matches_credentials (initial_response, _g_dbus_auth_mechanism_get_credentials (mechanism)))
237         {
238           m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
239         }
240       else
241         {
242           m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
243         }
244     }
245   else
246     {
247       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
248     }
249 }
250
251 static void
252 mechanism_server_data_receive (GDBusAuthMechanism   *mechanism,
253                                const gchar          *data,
254                                gsize                 data_len)
255 {
256   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
257
258   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
259   g_return_if_fail (m->priv->is_server && !m->priv->is_client);
260   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
261
262   if (data_matches_credentials (data, _g_dbus_auth_mechanism_get_credentials (mechanism)))
263     {
264       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
265     }
266   else
267     {
268       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
269     }
270 }
271
272 static gchar *
273 mechanism_server_data_send (GDBusAuthMechanism   *mechanism,
274                             gsize                *out_data_len)
275 {
276   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
277
278   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
279   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
280   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
281
282   /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
283   g_assert_not_reached ();
284
285   return NULL;
286 }
287
288 static gchar *
289 mechanism_server_get_reject_reason (GDBusAuthMechanism   *mechanism)
290 {
291   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
292
293   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
294   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
295   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
296
297   /* can never end up here because we are never in the REJECTED state */
298   g_assert_not_reached ();
299
300   return NULL;
301 }
302
303 static void
304 mechanism_server_shutdown (GDBusAuthMechanism   *mechanism)
305 {
306   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
307
308   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
309   g_return_if_fail (m->priv->is_server && !m->priv->is_client);
310
311   m->priv->is_server = FALSE;
312 }
313
314 /* ---------------------------------------------------------------------------------------------------- */
315
316 static GDBusAuthMechanismState
317 mechanism_client_get_state (GDBusAuthMechanism   *mechanism)
318 {
319   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
320
321   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
322   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
323
324   return m->priv->state;
325 }
326
327 static gchar *
328 mechanism_client_initiate (GDBusAuthMechanism   *mechanism,
329                            gsize                *out_initial_response_len)
330 {
331   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
332   gchar *initial_response;
333   GCredentials *credentials;
334
335   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
336   g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
337
338   m->priv->is_client = TRUE;
339   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
340
341   *out_initial_response_len = -1;
342
343   credentials = _g_dbus_auth_mechanism_get_credentials (mechanism);
344   g_assert (credentials != NULL);
345
346   /* return the uid */
347 #if defined(G_OS_UNIX)
348   initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL));
349 #elif defined(G_OS_WIN32)
350 #ifdef __GNUC__
351 #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work.
352 #endif
353   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
354 #endif
355   return initial_response;
356 }
357
358 static void
359 mechanism_client_data_receive (GDBusAuthMechanism   *mechanism,
360                                const gchar          *data,
361                                gsize                 data_len)
362 {
363   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
364
365   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
366   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
367   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
368
369   /* can never end up here because we are never in the WAITING_FOR_DATA state */
370   g_assert_not_reached ();
371 }
372
373 static gchar *
374 mechanism_client_data_send (GDBusAuthMechanism   *mechanism,
375                             gsize                *out_data_len)
376 {
377   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
378
379   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
380   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
381   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
382
383   /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
384   g_assert_not_reached ();
385
386   return NULL;
387 }
388
389 static void
390 mechanism_client_shutdown (GDBusAuthMechanism   *mechanism)
391 {
392   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
393
394   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
395   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
396
397   m->priv->is_client = FALSE;
398 }
399
400 /* ---------------------------------------------------------------------------------------------------- */