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