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