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