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