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