Implement bash completion for gsettings
[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 #include "gioalias.h"
38
39 struct _GDBusAuthMechanismExternalPrivate
40 {
41   gboolean is_client;
42   gboolean is_server;
43   GDBusAuthMechanismState state;
44 };
45
46 static gint                     mechanism_get_priority              (void);
47 static const gchar             *mechanism_get_name                  (void);
48
49 static gboolean                 mechanism_is_supported              (GDBusAuthMechanism   *mechanism);
50 static gchar                   *mechanism_encode_data               (GDBusAuthMechanism   *mechanism,
51                                                                      const gchar          *data,
52                                                                      gsize                 data_len,
53                                                                      gsize                *out_data_len);
54 static gchar                   *mechanism_decode_data               (GDBusAuthMechanism   *mechanism,
55                                                                      const gchar          *data,
56                                                                      gsize                 data_len,
57                                                                      gsize                *out_data_len);
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,
63                                                                      const gchar          *data,
64                                                                      gsize                 data_len);
65 static gchar                   *mechanism_server_data_send          (GDBusAuthMechanism   *mechanism,
66                                                                      gsize                *out_data_len);
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,
73                                                                      const gchar          *data,
74                                                                      gsize                 data_len);
75 static gchar                   *mechanism_client_data_send          (GDBusAuthMechanism   *mechanism,
76                                                                      gsize                *out_data_len);
77 static void                     mechanism_client_shutdown           (GDBusAuthMechanism   *mechanism);
78
79 /* ---------------------------------------------------------------------------------------------------- */
80
81 G_DEFINE_TYPE (GDBusAuthMechanismExternal, _g_dbus_auth_mechanism_external, G_TYPE_DBUS_AUTH_MECHANISM);
82
83 /* ---------------------------------------------------------------------------------------------------- */
84
85 static void
86 _g_dbus_auth_mechanism_external_finalize (GObject *object)
87 {
88   //GDBusAuthMechanismExternal *mechanism = G_DBUS_AUTH_MECHANISM_EXTERNAL (object);
89
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);
92 }
93
94 static void
95 _g_dbus_auth_mechanism_external_class_init (GDBusAuthMechanismExternalClass *klass)
96 {
97   GObjectClass *gobject_class;
98   GDBusAuthMechanismClass *mechanism_class;
99
100   g_type_class_add_private (klass, sizeof (GDBusAuthMechanismExternalPrivate));
101
102   gobject_class = G_OBJECT_CLASS (klass);
103   gobject_class->finalize = _g_dbus_auth_mechanism_external_finalize;
104
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;
122 }
123
124 static void
125 _g_dbus_auth_mechanism_external_init (GDBusAuthMechanismExternal *mechanism)
126 {
127   mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
128                                                  G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL,
129                                                  GDBusAuthMechanismExternalPrivate);
130 }
131
132 /* ---------------------------------------------------------------------------------------------------- */
133
134 static gboolean
135 mechanism_is_supported (GDBusAuthMechanism *mechanism)
136 {
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)
140     return TRUE;
141   else
142     return FALSE;
143 }
144
145 static gint
146 mechanism_get_priority (void)
147 {
148   /* We prefer EXTERNAL to most other mechanism (DBUS_COOKIE_SHA1 and ANONYMOUS) */
149   return 100;
150 }
151
152 static const gchar *
153 mechanism_get_name (void)
154 {
155   return "EXTERNAL";
156 }
157
158 static gchar *
159 mechanism_encode_data (GDBusAuthMechanism   *mechanism,
160                        const gchar          *data,
161                        gsize                 data_len,
162                        gsize                *out_data_len)
163 {
164   return NULL;
165 }
166
167
168 static gchar *
169 mechanism_decode_data (GDBusAuthMechanism   *mechanism,
170                        const gchar          *data,
171                        gsize                 data_len,
172                        gsize                *out_data_len)
173 {
174   return NULL;
175 }
176
177 /* ---------------------------------------------------------------------------------------------------- */
178
179 static GDBusAuthMechanismState
180 mechanism_server_get_state (GDBusAuthMechanism   *mechanism)
181 {
182   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
183
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);
186
187   return m->priv->state;
188 }
189
190 static gboolean
191 data_matches_credentials (const gchar *data,
192                           GCredentials *credentials)
193 {
194   gboolean match;
195
196   match = FALSE;
197
198   if (credentials == NULL)
199     goto out;
200
201   if (data == NULL || strlen (data) == 0)
202     goto out;
203
204 #if defined(G_OS_UNIX)
205   {
206     gint64 alleged_uid;
207     gchar *endp;
208
209     /* on UNIX, this is the uid as a string in base 10 */
210     alleged_uid = g_ascii_strtoll (data, &endp, 10);
211     if (*endp == '\0')
212       {
213         if (g_credentials_get_unix_user (credentials, NULL) == alleged_uid)
214           {
215             match = TRUE;
216           }
217       }
218   }
219 #else
220   /* TODO: Dont know how to compare credentials on this OS. Please implement. */
221 #endif
222
223  out:
224   return match;
225 }
226
227 static void
228 mechanism_server_initiate (GDBusAuthMechanism   *mechanism,
229                            const gchar          *initial_response,
230                            gsize                 initial_response_len)
231 {
232   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
233
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);
236
237   m->priv->is_server = TRUE;
238
239   if (initial_response != NULL)
240     {
241       if (data_matches_credentials (initial_response, _g_dbus_auth_mechanism_get_credentials (mechanism)))
242         {
243           m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
244         }
245       else
246         {
247           m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
248         }
249     }
250   else
251     {
252       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
253     }
254 }
255
256 static void
257 mechanism_server_data_receive (GDBusAuthMechanism   *mechanism,
258                                const gchar          *data,
259                                gsize                 data_len)
260 {
261   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
262
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);
266
267   if (data_matches_credentials (data, _g_dbus_auth_mechanism_get_credentials (mechanism)))
268     {
269       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
270     }
271   else
272     {
273       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
274     }
275 }
276
277 static gchar *
278 mechanism_server_data_send (GDBusAuthMechanism   *mechanism,
279                             gsize                *out_data_len)
280 {
281   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
282
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);
286
287   /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
288   g_assert_not_reached ();
289
290   return NULL;
291 }
292
293 static gchar *
294 mechanism_server_get_reject_reason (GDBusAuthMechanism   *mechanism)
295 {
296   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
297
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);
301
302   /* can never end up here because we are never in the REJECTED state */
303   g_assert_not_reached ();
304
305   return NULL;
306 }
307
308 static void
309 mechanism_server_shutdown (GDBusAuthMechanism   *mechanism)
310 {
311   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
312
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);
315
316   m->priv->is_server = FALSE;
317 }
318
319 /* ---------------------------------------------------------------------------------------------------- */
320
321 static GDBusAuthMechanismState
322 mechanism_client_get_state (GDBusAuthMechanism   *mechanism)
323 {
324   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
325
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);
328
329   return m->priv->state;
330 }
331
332 static gchar *
333 mechanism_client_initiate (GDBusAuthMechanism   *mechanism,
334                            gsize                *out_initial_response_len)
335 {
336   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
337   gchar *initial_response;
338   GCredentials *credentials;
339
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);
342
343   m->priv->is_client = TRUE;
344   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
345
346   *out_initial_response_len = -1;
347
348   credentials = _g_dbus_auth_mechanism_get_credentials (mechanism);
349   g_assert (credentials != NULL);
350
351   /* return the uid */
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 #ifdef __GNUC__
356 #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work.
357 #endif
358   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
359 #endif
360   return initial_response;
361 }
362
363 static void
364 mechanism_client_data_receive (GDBusAuthMechanism   *mechanism,
365                                const gchar          *data,
366                                gsize                 data_len)
367 {
368   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
369
370   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
371   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
372   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
373
374   /* can never end up here because we are never in the WAITING_FOR_DATA state */
375   g_assert_not_reached ();
376 }
377
378 static gchar *
379 mechanism_client_data_send (GDBusAuthMechanism   *mechanism,
380                             gsize                *out_data_len)
381 {
382   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
383
384   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
385   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
386   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
387
388   /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
389   g_assert_not_reached ();
390
391   return NULL;
392 }
393
394 static void
395 mechanism_client_shutdown (GDBusAuthMechanism   *mechanism)
396 {
397   GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
398
399   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
400   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
401
402   m->priv->is_client = FALSE;
403 }
404
405 /* ---------------------------------------------------------------------------------------------------- */
406
407 #define __G_DBUS_AUTH_MECHANISM_EXTERNAL_C__
408 #include "gioaliasdef.c"