nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | #include <fcntl.h> |
||
25 | #include <errno.h> |
||
26 | #include <sys/types.h> |
||
27 | |||
28 | #include <glib/gstdio.h> |
||
29 | |||
30 | #ifdef G_OS_UNIX |
||
31 | #include <unistd.h> |
||
32 | #endif |
||
33 | #ifdef G_OS_WIN32 |
||
34 | #include <io.h> |
||
35 | #endif |
||
36 | |||
37 | #include "gdbusauthmechanismsha1.h" |
||
38 | #include "gcredentials.h" |
||
39 | #include "gdbuserror.h" |
||
40 | #include "gioenumtypes.h" |
||
41 | #include "gioerror.h" |
||
42 | #include "gdbusprivate.h" |
||
43 | |||
44 | #include "glibintl.h" |
||
45 | |||
46 | struct _GDBusAuthMechanismSha1Private |
||
47 | { |
||
48 | gboolean is_client; |
||
49 | gboolean is_server; |
||
50 | GDBusAuthMechanismState state; |
||
51 | |||
52 | /* used on the client side */ |
||
53 | gchar *to_send; |
||
54 | |||
55 | /* used on the server side */ |
||
56 | gchar *cookie; |
||
57 | gchar *server_challenge; |
||
58 | }; |
||
59 | |||
60 | static gint mechanism_get_priority (void); |
||
61 | static const gchar *mechanism_get_name (void); |
||
62 | |||
63 | static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism); |
||
64 | static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism, |
||
65 | const gchar *data, |
||
66 | gsize data_len, |
||
67 | gsize *out_data_len); |
||
68 | static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism, |
||
69 | const gchar *data, |
||
70 | gsize data_len, |
||
71 | gsize *out_data_len); |
||
72 | static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism); |
||
73 | static void mechanism_server_initiate (GDBusAuthMechanism *mechanism, |
||
74 | const gchar *initial_response, |
||
75 | gsize initial_response_len); |
||
76 | static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism, |
||
77 | const gchar *data, |
||
78 | gsize data_len); |
||
79 | static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism, |
||
80 | gsize *out_data_len); |
||
81 | static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism); |
||
82 | static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism); |
||
83 | static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism); |
||
84 | static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism, |
||
85 | gsize *out_initial_response_len); |
||
86 | static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism, |
||
87 | const gchar *data, |
||
88 | gsize data_len); |
||
89 | static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism, |
||
90 | gsize *out_data_len); |
||
91 | static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism); |
||
92 | |||
93 | /* ---------------------------------------------------------------------------------------------------- */ |
||
94 | |||
95 | G_DEFINE_TYPE_WITH_PRIVATE (GDBusAuthMechanismSha1, _g_dbus_auth_mechanism_sha1, G_TYPE_DBUS_AUTH_MECHANISM) |
||
96 | |||
97 | /* ---------------------------------------------------------------------------------------------------- */ |
||
98 | |||
99 | static void |
||
100 | _g_dbus_auth_mechanism_sha1_finalize (GObject *object) |
||
101 | { |
||
102 | GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object); |
||
103 | |||
104 | g_free (mechanism->priv->to_send); |
||
105 | |||
106 | g_free (mechanism->priv->cookie); |
||
107 | g_free (mechanism->priv->server_challenge); |
||
108 | |||
109 | if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize != NULL) |
||
110 | G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize (object); |
||
111 | } |
||
112 | |||
113 | static void |
||
114 | _g_dbus_auth_mechanism_sha1_class_init (GDBusAuthMechanismSha1Class *klass) |
||
115 | { |
||
116 | GObjectClass *gobject_class; |
||
117 | GDBusAuthMechanismClass *mechanism_class; |
||
118 | |||
119 | gobject_class = G_OBJECT_CLASS (klass); |
||
120 | gobject_class->finalize = _g_dbus_auth_mechanism_sha1_finalize; |
||
121 | |||
122 | mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass); |
||
123 | mechanism_class->get_priority = mechanism_get_priority; |
||
124 | mechanism_class->get_name = mechanism_get_name; |
||
125 | mechanism_class->is_supported = mechanism_is_supported; |
||
126 | mechanism_class->encode_data = mechanism_encode_data; |
||
127 | mechanism_class->decode_data = mechanism_decode_data; |
||
128 | mechanism_class->server_get_state = mechanism_server_get_state; |
||
129 | mechanism_class->server_initiate = mechanism_server_initiate; |
||
130 | mechanism_class->server_data_receive = mechanism_server_data_receive; |
||
131 | mechanism_class->server_data_send = mechanism_server_data_send; |
||
132 | mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason; |
||
133 | mechanism_class->server_shutdown = mechanism_server_shutdown; |
||
134 | mechanism_class->client_get_state = mechanism_client_get_state; |
||
135 | mechanism_class->client_initiate = mechanism_client_initiate; |
||
136 | mechanism_class->client_data_receive = mechanism_client_data_receive; |
||
137 | mechanism_class->client_data_send = mechanism_client_data_send; |
||
138 | mechanism_class->client_shutdown = mechanism_client_shutdown; |
||
139 | } |
||
140 | |||
141 | static void |
||
142 | _g_dbus_auth_mechanism_sha1_init (GDBusAuthMechanismSha1 *mechanism) |
||
143 | { |
||
144 | mechanism->priv = _g_dbus_auth_mechanism_sha1_get_instance_private (mechanism); |
||
145 | } |
||
146 | |||
147 | /* ---------------------------------------------------------------------------------------------------- */ |
||
148 | |||
149 | static gint |
||
150 | mechanism_get_priority (void) |
||
151 | { |
||
152 | return 0; |
||
153 | } |
||
154 | |||
155 | static const gchar * |
||
156 | mechanism_get_name (void) |
||
157 | { |
||
158 | return "DBUS_COOKIE_SHA1"; |
||
159 | } |
||
160 | |||
161 | static gboolean |
||
162 | mechanism_is_supported (GDBusAuthMechanism *mechanism) |
||
163 | { |
||
164 | g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), FALSE); |
||
165 | return TRUE; |
||
166 | } |
||
167 | |||
168 | static gchar * |
||
169 | mechanism_encode_data (GDBusAuthMechanism *mechanism, |
||
170 | const gchar *data, |
||
171 | gsize data_len, |
||
172 | gsize *out_data_len) |
||
173 | { |
||
174 | return NULL; |
||
175 | } |
||
176 | |||
177 | |||
178 | static gchar * |
||
179 | mechanism_decode_data (GDBusAuthMechanism *mechanism, |
||
180 | const gchar *data, |
||
181 | gsize data_len, |
||
182 | gsize *out_data_len) |
||
183 | { |
||
184 | return NULL; |
||
185 | } |
||
186 | |||
187 | /* ---------------------------------------------------------------------------------------------------- */ |
||
188 | |||
189 | static gint |
||
190 | random_ascii (void) |
||
191 | { |
||
192 | gint ret; |
||
193 | ret = g_random_int_range (0, 60); |
||
194 | if (ret < 25) |
||
195 | ret += 'A'; |
||
196 | else if (ret < 50) |
||
197 | ret += 'a' - 25; |
||
198 | else |
||
199 | ret += '0' - 50; |
||
200 | return ret; |
||
201 | } |
||
202 | |||
203 | static gchar * |
||
204 | random_ascii_string (guint len) |
||
205 | { |
||
206 | GString *challenge; |
||
207 | guint n; |
||
208 | |||
209 | challenge = g_string_new (NULL); |
||
210 | for (n = 0; n < len; n++) |
||
211 | g_string_append_c (challenge, random_ascii ()); |
||
212 | return g_string_free (challenge, FALSE); |
||
213 | } |
||
214 | |||
215 | static gchar * |
||
216 | random_blob (guint len) |
||
217 | { |
||
218 | GString *challenge; |
||
219 | guint n; |
||
220 | |||
221 | challenge = g_string_new (NULL); |
||
222 | for (n = 0; n < len; n++) |
||
223 | g_string_append_c (challenge, g_random_int_range (0, 256)); |
||
224 | return g_string_free (challenge, FALSE); |
||
225 | } |
||
226 | |||
227 | /* ---------------------------------------------------------------------------------------------------- */ |
||
228 | |||
229 | /* ensure keyring dir exists and permissions are correct */ |
||
230 | static gchar * |
||
231 | ensure_keyring_directory (GError **error) |
||
232 | { |
||
233 | gchar *path; |
||
234 | const gchar *e; |
||
235 | |||
236 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
||
237 | |||
238 | e = g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR"); |
||
239 | if (e != NULL) |
||
240 | { |
||
241 | path = g_strdup (e); |
||
242 | } |
||
243 | else |
||
244 | { |
||
245 | path = g_build_filename (g_get_home_dir (), |
||
246 | ".dbus-keyrings", |
||
247 | NULL); |
||
248 | } |
||
249 | |||
250 | if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) |
||
251 | { |
||
252 | if (g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION") == NULL) |
||
253 | { |
||
254 | #ifdef G_OS_UNIX |
||
255 | struct stat statbuf; |
||
256 | if (stat (path, &statbuf) != 0) |
||
257 | { |
||
258 | g_set_error (error, |
||
259 | G_IO_ERROR, |
||
260 | g_io_error_from_errno (errno), |
||
261 | _("Error when getting information for directory '%s': %s"), |
||
262 | path, |
||
263 | strerror (errno)); |
||
264 | g_free (path); |
||
265 | path = NULL; |
||
266 | goto out; |
||
267 | } |
||
268 | if ((statbuf.st_mode & 0777) != 0700) |
||
269 | { |
||
270 | g_set_error (error, |
||
271 | G_IO_ERROR, |
||
272 | G_IO_ERROR_FAILED, |
||
273 | _("Permissions on directory '%s' are malformed. Expected mode 0700, got 0%o"), |
||
274 | path, |
||
275 | statbuf.st_mode & 0777); |
||
276 | g_free (path); |
||
277 | path = NULL; |
||
278 | goto out; |
||
279 | } |
||
280 | #else |
||
281 | #ifdef __GNUC__ |
||
282 | #warning Please implement permission checking on this non-UNIX platform |
||
283 | #endif |
||
284 | #endif |
||
285 | } |
||
286 | goto out; |
||
287 | } |
||
288 | |||
289 | if (g_mkdir (path, 0700) != 0) |
||
290 | { |
||
291 | g_set_error (error, |
||
292 | G_IO_ERROR, |
||
293 | g_io_error_from_errno (errno), |
||
294 | _("Error creating directory '%s': %s"), |
||
295 | path, |
||
296 | strerror (errno)); |
||
297 | g_free (path); |
||
298 | path = NULL; |
||
299 | goto out; |
||
300 | } |
||
301 | |||
302 | out: |
||
303 | return path; |
||
304 | } |
||
305 | |||
306 | /* ---------------------------------------------------------------------------------------------------- */ |
||
307 | |||
308 | static void |
||
309 | append_nibble (GString *s, gint val) |
||
310 | { |
||
311 | g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val)); |
||
312 | } |
||
313 | |||
314 | static gchar * |
||
315 | hexencode (const gchar *str, |
||
316 | gssize len) |
||
317 | { |
||
318 | guint n; |
||
319 | GString *s; |
||
320 | |||
321 | if (len == -1) |
||
322 | len = strlen (str); |
||
323 | |||
324 | s = g_string_new (NULL); |
||
325 | for (n = 0; n < len; n++) |
||
326 | { |
||
327 | gint val; |
||
328 | gint upper_nibble; |
||
329 | gint lower_nibble; |
||
330 | |||
331 | val = ((const guchar *) str)[n]; |
||
332 | upper_nibble = val >> 4; |
||
333 | lower_nibble = val & 0x0f; |
||
334 | |||
335 | append_nibble (s, upper_nibble); |
||
336 | append_nibble (s, lower_nibble); |
||
337 | } |
||
338 | |||
339 | return g_string_free (s, FALSE); |
||
340 | } |
||
341 | |||
342 | /* ---------------------------------------------------------------------------------------------------- */ |
||
343 | |||
344 | /* looks up an entry in the keyring */ |
||
345 | static gchar * |
||
346 | keyring_lookup_entry (const gchar *cookie_context, |
||
347 | gint cookie_id, |
||
348 | GError **error) |
||
349 | { |
||
350 | gchar *ret; |
||
351 | gchar *keyring_dir; |
||
352 | gchar *contents; |
||
353 | gchar *path; |
||
354 | guint n; |
||
355 | gchar **lines; |
||
356 | |||
357 | g_return_val_if_fail (cookie_context != NULL, NULL); |
||
358 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
||
359 | |||
360 | ret = NULL; |
||
361 | path = NULL; |
||
362 | contents = NULL; |
||
363 | lines = NULL; |
||
364 | |||
365 | keyring_dir = ensure_keyring_directory (error); |
||
366 | if (keyring_dir == NULL) |
||
367 | goto out; |
||
368 | |||
369 | path = g_build_filename (keyring_dir, cookie_context, NULL); |
||
370 | |||
371 | if (!g_file_get_contents (path, |
||
372 | &contents, |
||
373 | NULL, |
||
374 | error)) |
||
375 | { |
||
376 | g_prefix_error (error, |
||
377 | _("Error opening keyring '%s' for reading: "), |
||
378 | path); |
||
379 | goto out; |
||
380 | } |
||
381 | g_assert (contents != NULL); |
||
382 | |||
383 | lines = g_strsplit (contents, "\n", 0); |
||
384 | for (n = 0; lines[n] != NULL; n++) |
||
385 | { |
||
386 | const gchar *line = lines[n]; |
||
387 | gchar **tokens; |
||
388 | gchar *endp; |
||
389 | gint line_id; |
||
390 | guint64 line_when; |
||
391 | |||
392 | if (line[0] == '\0') |
||
393 | continue; |
||
394 | |||
395 | tokens = g_strsplit (line, " ", 0); |
||
396 | if (g_strv_length (tokens) != 3) |
||
397 | { |
||
398 | g_set_error (error, |
||
399 | G_IO_ERROR, |
||
400 | G_IO_ERROR_FAILED, |
||
401 | _("Line %d of the keyring at '%s' with content '%s' is malformed"), |
||
402 | n + 1, |
||
403 | path, |
||
404 | line); |
||
405 | g_strfreev (tokens); |
||
406 | goto out; |
||
407 | } |
||
408 | |||
409 | line_id = g_ascii_strtoll (tokens[0], &endp, 10); |
||
410 | if (*endp != '\0') |
||
411 | { |
||
412 | g_set_error (error, |
||
413 | G_IO_ERROR, |
||
414 | G_IO_ERROR_FAILED, |
||
415 | _("First token of line %d of the keyring at '%s' with content '%s' is malformed"), |
||
416 | n + 1, |
||
417 | path, |
||
418 | line); |
||
419 | g_strfreev (tokens); |
||
420 | goto out; |
||
421 | } |
||
422 | |||
423 | line_when = g_ascii_strtoll (tokens[1], &endp, 10); |
||
424 | line_when = line_when; /* To avoid -Wunused-but-set-variable */ |
||
425 | if (*endp != '\0') |
||
426 | { |
||
427 | g_set_error (error, |
||
428 | G_IO_ERROR, |
||
429 | G_IO_ERROR_FAILED, |
||
430 | _("Second token of line %d of the keyring at '%s' with content '%s' is malformed"), |
||
431 | n + 1, |
||
432 | path, |
||
433 | line); |
||
434 | g_strfreev (tokens); |
||
435 | goto out; |
||
436 | } |
||
437 | |||
438 | if (line_id == cookie_id) |
||
439 | { |
||
440 | /* YAY, success */ |
||
441 | ret = tokens[2]; /* steal pointer */ |
||
442 | tokens[2] = NULL; |
||
443 | g_strfreev (tokens); |
||
444 | goto out; |
||
445 | } |
||
446 | |||
447 | g_strfreev (tokens); |
||
448 | } |
||
449 | |||
450 | /* BOOH, didn't find the cookie */ |
||
451 | g_set_error (error, |
||
452 | G_IO_ERROR, |
||
453 | G_IO_ERROR_FAILED, |
||
454 | _("Didn't find cookie with id %d in the keyring at '%s'"), |
||
455 | cookie_id, |
||
456 | path); |
||
457 | |||
458 | out: |
||
459 | g_free (keyring_dir); |
||
460 | g_free (path); |
||
461 | g_free (contents); |
||
462 | g_strfreev (lines); |
||
463 | return ret; |
||
464 | } |
||
465 | |||
466 | /* function for logging important events that the system administrator should take notice of */ |
||
467 | G_GNUC_PRINTF(1, 2) |
||
468 | static void |
||
469 | _log (const gchar *message, |
||
470 | ...) |
||
471 | { |
||
472 | gchar *s; |
||
473 | va_list var_args; |
||
474 | |||
475 | va_start (var_args, message); |
||
476 | s = g_strdup_vprintf (message, var_args); |
||
477 | va_end (var_args); |
||
478 | |||
479 | /* TODO: might want to send this to syslog instead */ |
||
480 | g_printerr ("GDBus-DBUS_COOKIE_SHA1: %s\n", s); |
||
481 | g_free (s); |
||
482 | } |
||
483 | |||
484 | static gint |
||
485 | keyring_acquire_lock (const gchar *path, |
||
486 | GError **error) |
||
487 | { |
||
488 | gchar *lock; |
||
489 | gint ret; |
||
490 | guint num_tries; |
||
491 | guint num_create_tries; |
||
492 | |||
493 | g_return_val_if_fail (path != NULL, FALSE); |
||
494 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
495 | |||
496 | ret = -1; |
||
497 | lock = g_strdup_printf ("%s.lock", path); |
||
498 | |||
499 | /* This is what the D-Bus spec says |
||
500 | * |
||
501 | * Create a lockfile name by appending ".lock" to the name of the |
||
502 | * cookie file. The server should attempt to create this file using |
||
503 | * O_CREAT | O_EXCL. If file creation fails, the lock |
||
504 | * fails. Servers should retry for a reasonable period of time, |
||
505 | * then they may choose to delete an existing lock to keep users |
||
506 | * from having to manually delete a stale lock. [1] |
||
507 | * |
||
508 | * [1] : Lockfiles are used instead of real file locking fcntl() because |
||
509 | * real locking implementations are still flaky on network filesystems |
||
510 | */ |
||
511 | |||
512 | num_create_tries = 0; |
||
513 | #ifdef EEXISTS |
||
514 | again: |
||
515 | #endif |
||
516 | num_tries = 0; |
||
517 | while (g_file_test (lock, G_FILE_TEST_EXISTS)) |
||
518 | { |
||
519 | /* sleep 10ms, then try again */ |
||
520 | g_usleep (1000*10); |
||
521 | num_tries++; |
||
522 | if (num_tries == 50) |
||
523 | { |
||
524 | /* ok, we slept 50*10ms = 0.5 seconds. Conclude that the lock file must be |
||
525 | * stale (nuke the it from orbit) |
||
526 | */ |
||
527 | if (g_unlink (lock) != 0) |
||
528 | { |
||
529 | g_set_error (error, |
||
530 | G_IO_ERROR, |
||
531 | g_io_error_from_errno (errno), |
||
532 | _("Error deleting stale lock file '%s': %s"), |
||
533 | lock, |
||
534 | strerror (errno)); |
||
535 | goto out; |
||
536 | } |
||
537 | _log ("Deleted stale lock file '%s'", lock); |
||
538 | break; |
||
539 | } |
||
540 | } |
||
541 | |||
542 | ret = g_open (lock, O_CREAT | |
||
543 | #ifdef O_EXCL |
||
544 | O_EXCL, |
||
545 | #else |
||
546 | 0, |
||
547 | #endif |
||
548 | 0700); |
||
549 | if (ret == -1) |
||
550 | { |
||
551 | #ifdef EEXISTS |
||
552 | /* EEXIST: pathname already exists and O_CREAT and O_EXCL were used. */ |
||
553 | if (errno == EEXISTS) |
||
554 | { |
||
555 | num_create_tries++; |
||
556 | if (num_create_tries < 5) |
||
557 | goto again; |
||
558 | } |
||
559 | #endif |
||
560 | num_create_tries = num_create_tries; /* To avoid -Wunused-but-set-variable */ |
||
561 | g_set_error (error, |
||
562 | G_IO_ERROR, |
||
563 | g_io_error_from_errno (errno), |
||
564 | _("Error creating lock file '%s': %s"), |
||
565 | lock, |
||
566 | strerror (errno)); |
||
567 | goto out; |
||
568 | } |
||
569 | |||
570 | out: |
||
571 | g_free (lock); |
||
572 | return ret; |
||
573 | } |
||
574 | |||
575 | static gboolean |
||
576 | keyring_release_lock (const gchar *path, |
||
577 | gint lock_fd, |
||
578 | GError **error) |
||
579 | { |
||
580 | gchar *lock; |
||
581 | gboolean ret; |
||
582 | |||
583 | g_return_val_if_fail (path != NULL, FALSE); |
||
584 | g_return_val_if_fail (lock_fd != -1, FALSE); |
||
585 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
586 | |||
587 | ret = FALSE; |
||
588 | lock = g_strdup_printf ("%s.lock", path); |
||
589 | if (close (lock_fd) != 0) |
||
590 | { |
||
591 | g_set_error (error, |
||
592 | G_IO_ERROR, |
||
593 | g_io_error_from_errno (errno), |
||
594 | _("Error closing (unlinked) lock file '%s': %s"), |
||
595 | lock, |
||
596 | strerror (errno)); |
||
597 | goto out; |
||
598 | } |
||
599 | if (g_unlink (lock) != 0) |
||
600 | { |
||
601 | g_set_error (error, |
||
602 | G_IO_ERROR, |
||
603 | g_io_error_from_errno (errno), |
||
604 | _("Error unlinking lock file '%s': %s"), |
||
605 | lock, |
||
606 | strerror (errno)); |
||
607 | goto out; |
||
608 | } |
||
609 | |||
610 | ret = TRUE; |
||
611 | |||
612 | out: |
||
613 | g_free (lock); |
||
614 | return ret; |
||
615 | } |
||
616 | |||
617 | |||
618 | /* adds an entry to the keyring, taking care of locking and deleting stale/future entries */ |
||
619 | static gboolean |
||
620 | keyring_generate_entry (const gchar *cookie_context, |
||
621 | gint *out_id, |
||
622 | gchar **out_cookie, |
||
623 | GError **error) |
||
624 | { |
||
625 | gboolean ret; |
||
626 | gchar *keyring_dir; |
||
627 | gchar *path; |
||
628 | gchar *contents; |
||
629 | GError *local_error; |
||
630 | gchar **lines; |
||
631 | gint max_line_id; |
||
632 | GString *new_contents; |
||
633 | guint64 now; |
||
634 | gboolean have_id; |
||
635 | gint use_id; |
||
636 | gchar *use_cookie; |
||
637 | gboolean changed_file; |
||
638 | gint lock_fd; |
||
639 | |||
640 | g_return_val_if_fail (cookie_context != NULL, FALSE); |
||
641 | g_return_val_if_fail (out_id != NULL, FALSE); |
||
642 | g_return_val_if_fail (out_cookie != NULL, FALSE); |
||
643 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
644 | |||
645 | ret = FALSE; |
||
646 | path = NULL; |
||
647 | contents = NULL; |
||
648 | lines = NULL; |
||
649 | new_contents = NULL; |
||
650 | have_id = FALSE; |
||
651 | use_id = 0; |
||
652 | use_cookie = NULL; |
||
653 | lock_fd = -1; |
||
654 | |||
655 | keyring_dir = ensure_keyring_directory (error); |
||
656 | if (keyring_dir == NULL) |
||
657 | goto out; |
||
658 | |||
659 | path = g_build_filename (keyring_dir, cookie_context, NULL); |
||
660 | |||
661 | lock_fd = keyring_acquire_lock (path, error); |
||
662 | if (lock_fd == -1) |
||
663 | goto out; |
||
664 | |||
665 | local_error = NULL; |
||
666 | contents = NULL; |
||
667 | if (!g_file_get_contents (path, |
||
668 | &contents, |
||
669 | NULL, |
||
670 | &local_error)) |
||
671 | { |
||
672 | if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT) |
||
673 | { |
||
674 | /* file doesn't have to exist */ |
||
675 | g_error_free (local_error); |
||
676 | } |
||
677 | else |
||
678 | { |
||
679 | g_propagate_prefixed_error (error, |
||
680 | local_error, |
||
681 | _("Error opening keyring '%s' for writing: "), |
||
682 | path); |
||
683 | goto out; |
||
684 | } |
||
685 | } |
||
686 | |||
687 | new_contents = g_string_new (NULL); |
||
688 | now = time (NULL); |
||
689 | changed_file = FALSE; |
||
690 | |||
691 | max_line_id = 0; |
||
692 | if (contents != NULL) |
||
693 | { |
||
694 | guint n; |
||
695 | lines = g_strsplit (contents, "\n", 0); |
||
696 | for (n = 0; lines[n] != NULL; n++) |
||
697 | { |
||
698 | const gchar *line = lines[n]; |
||
699 | gchar **tokens; |
||
700 | gchar *endp; |
||
701 | gint line_id; |
||
702 | guint64 line_when; |
||
703 | gboolean keep_entry; |
||
704 | |||
705 | if (line[0] == '\0') |
||
706 | continue; |
||
707 | |||
708 | tokens = g_strsplit (line, " ", 0); |
||
709 | if (g_strv_length (tokens) != 3) |
||
710 | { |
||
711 | g_set_error (error, |
||
712 | G_IO_ERROR, |
||
713 | G_IO_ERROR_FAILED, |
||
714 | _("Line %d of the keyring at '%s' with content '%s' is malformed"), |
||
715 | n + 1, |
||
716 | path, |
||
717 | line); |
||
718 | g_strfreev (tokens); |
||
719 | goto out; |
||
720 | } |
||
721 | |||
722 | line_id = g_ascii_strtoll (tokens[0], &endp, 10); |
||
723 | if (*endp != '\0') |
||
724 | { |
||
725 | g_set_error (error, |
||
726 | G_IO_ERROR, |
||
727 | G_IO_ERROR_FAILED, |
||
728 | _("First token of line %d of the keyring at '%s' with content '%s' is malformed"), |
||
729 | n + 1, |
||
730 | path, |
||
731 | line); |
||
732 | g_strfreev (tokens); |
||
733 | goto out; |
||
734 | } |
||
735 | |||
736 | line_when = g_ascii_strtoll (tokens[1], &endp, 10); |
||
737 | if (*endp != '\0') |
||
738 | { |
||
739 | g_set_error (error, |
||
740 | G_IO_ERROR, |
||
741 | G_IO_ERROR_FAILED, |
||
742 | _("Second token of line %d of the keyring at '%s' with content '%s' is malformed"), |
||
743 | n + 1, |
||
744 | path, |
||
745 | line); |
||
746 | g_strfreev (tokens); |
||
747 | goto out; |
||
748 | } |
||
749 | line_when = line_when; /* To avoid -Wunused-but-set-variable */ |
||
750 | |||
751 | |||
752 | /* D-Bus spec says: |
||
753 | * |
||
754 | * Once the lockfile has been created, the server loads the |
||
755 | * cookie file. It should then delete any cookies that are |
||
756 | * old (the timeout can be fairly short), or more than a |
||
757 | * reasonable time in the future (so that cookies never |
||
758 | * accidentally become permanent, if the clock was set far |
||
759 | * into the future at some point). If no recent keys remain, |
||
760 | * the server may generate a new key. |
||
761 | * |
||
762 | */ |
||
763 | keep_entry = TRUE; |
||
764 | if (line_when > now) |
||
765 | { |
||
766 | /* Oddball case: entry is more recent than our current wall-clock time.. |
||
767 | * This is OK, it means that another server on another machine but with |
||
768 | * same $HOME wrote the entry. |
||
769 | * |
||
770 | * So discard the entry if it's more than 1 day in the future ("reasonable |
||
771 | * time in the future"). |
||
772 | */ |
||
773 | if (line_when - now > 24*60*60) |
||
774 | { |
||
775 | keep_entry = FALSE; |
||
776 | _log ("Deleted SHA1 cookie from %" G_GUINT64_FORMAT " seconds in the future", line_when - now); |
||
777 | } |
||
778 | } |
||
779 | else |
||
780 | { |
||
781 | /* Discard entry if it's older than 15 minutes ("can be fairly short") */ |
||
782 | if (now - line_when > 15*60) |
||
783 | { |
||
784 | keep_entry = FALSE; |
||
785 | } |
||
786 | } |
||
787 | |||
788 | if (!keep_entry) |
||
789 | { |
||
790 | changed_file = FALSE; |
||
791 | } |
||
792 | else |
||
793 | { |
||
794 | g_string_append_printf (new_contents, |
||
795 | "%d %" G_GUINT64_FORMAT " %s\n", |
||
796 | line_id, |
||
797 | line_when, |
||
798 | tokens[2]); |
||
799 | max_line_id = MAX (line_id, max_line_id); |
||
800 | /* Only reuse entry if not older than 10 minutes. |
||
801 | * |
||
802 | * (We need a bit of grace time compared to 15 minutes above.. otherwise |
||
803 | * there's a race where we reuse the 14min59.9 secs old entry and a |
||
804 | * split-second later another server purges the now 15 minute old entry.) |
||
805 | */ |
||
806 | if (now - line_when < 10 * 60) |
||
807 | { |
||
808 | if (!have_id) |
||
809 | { |
||
810 | use_id = line_id; |
||
811 | use_cookie = tokens[2]; /* steal memory */ |
||
812 | tokens[2] = NULL; |
||
813 | have_id = TRUE; |
||
814 | } |
||
815 | } |
||
816 | } |
||
817 | g_strfreev (tokens); |
||
818 | } |
||
819 | } /* for each line */ |
||
820 | |||
821 | ret = TRUE; |
||
822 | |||
823 | if (have_id) |
||
824 | { |
||
825 | *out_id = use_id; |
||
826 | *out_cookie = use_cookie; |
||
827 | use_cookie = NULL; |
||
828 | } |
||
829 | else |
||
830 | { |
||
831 | gchar *raw_cookie; |
||
832 | *out_id = max_line_id + 1; |
||
833 | raw_cookie = random_blob (32); |
||
834 | *out_cookie = hexencode (raw_cookie, 32); |
||
835 | g_free (raw_cookie); |
||
836 | |||
837 | g_string_append_printf (new_contents, |
||
838 | "%d %" G_GUINT64_FORMAT " %s\n", |
||
839 | *out_id, |
||
840 | (guint64) time (NULL), |
||
841 | *out_cookie); |
||
842 | changed_file = TRUE; |
||
843 | } |
||
844 | |||
845 | /* and now actually write the cookie file if there are changes (this is atomic) */ |
||
846 | if (changed_file) |
||
847 | { |
||
848 | if (!g_file_set_contents (path, |
||
849 | new_contents->str, |
||
850 | -1, |
||
851 | error)) |
||
852 | { |
||
853 | *out_id = 0; |
||
854 | *out_cookie = 0; |
||
855 | g_free (*out_cookie); |
||
856 | ret = FALSE; |
||
857 | goto out; |
||
858 | } |
||
859 | } |
||
860 | |||
861 | out: |
||
862 | |||
863 | if (lock_fd != -1) |
||
864 | { |
||
865 | GError *local_error; |
||
866 | local_error = NULL; |
||
867 | if (!keyring_release_lock (path, lock_fd, &local_error)) |
||
868 | { |
||
869 | if (error != NULL) |
||
870 | { |
||
871 | if (*error == NULL) |
||
872 | { |
||
873 | *error = local_error; |
||
874 | } |
||
875 | else |
||
876 | { |
||
877 | g_prefix_error (error, |
||
878 | _("(Additionally, releasing the lock for '%s' also failed: %s) "), |
||
879 | path, |
||
880 | local_error->message); |
||
881 | } |
||
882 | } |
||
883 | else |
||
884 | { |
||
885 | g_error_free (local_error); |
||
886 | } |
||
887 | } |
||
888 | } |
||
889 | |||
890 | g_free (keyring_dir); |
||
891 | g_free (path); |
||
892 | g_strfreev (lines); |
||
893 | g_free (contents); |
||
894 | if (new_contents != NULL) |
||
895 | g_string_free (new_contents, TRUE); |
||
896 | g_free (use_cookie); |
||
897 | return ret; |
||
898 | } |
||
899 | |||
900 | /* ---------------------------------------------------------------------------------------------------- */ |
||
901 | |||
902 | static gchar * |
||
903 | generate_sha1 (const gchar *server_challenge, |
||
904 | const gchar *client_challenge, |
||
905 | const gchar *cookie) |
||
906 | { |
||
907 | GString *str; |
||
908 | gchar *sha1; |
||
909 | |||
910 | str = g_string_new (server_challenge); |
||
911 | g_string_append_c (str, ':'); |
||
912 | g_string_append (str, client_challenge); |
||
913 | g_string_append_c (str, ':'); |
||
914 | g_string_append (str, cookie); |
||
915 | sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str->str, -1); |
||
916 | g_string_free (str, TRUE); |
||
917 | |||
918 | return sha1; |
||
919 | } |
||
920 | |||
921 | /* ---------------------------------------------------------------------------------------------------- */ |
||
922 | |||
923 | static GDBusAuthMechanismState |
||
924 | mechanism_server_get_state (GDBusAuthMechanism *mechanism) |
||
925 | { |
||
926 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
927 | |||
928 | g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID); |
||
929 | g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID); |
||
930 | |||
931 | return m->priv->state; |
||
932 | } |
||
933 | |||
934 | static void |
||
935 | mechanism_server_initiate (GDBusAuthMechanism *mechanism, |
||
936 | const gchar *initial_response, |
||
937 | gsize initial_response_len) |
||
938 | { |
||
939 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
940 | |||
941 | g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism)); |
||
942 | g_return_if_fail (!m->priv->is_server && !m->priv->is_client); |
||
943 | |||
944 | m->priv->is_server = TRUE; |
||
945 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; |
||
946 | |||
947 | if (initial_response != NULL && strlen (initial_response) > 0) |
||
948 | { |
||
949 | #ifdef G_OS_UNIX |
||
950 | gint64 uid; |
||
951 | gchar *endp; |
||
952 | |||
953 | uid = g_ascii_strtoll (initial_response, &endp, 10); |
||
954 | if (*endp == '\0') |
||
955 | { |
||
956 | if (uid == getuid ()) |
||
957 | { |
||
958 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND; |
||
959 | } |
||
960 | } |
||
961 | #elif defined(G_OS_WIN32) |
||
962 | gchar *sid; |
||
963 | sid = _g_dbus_win32_get_user_sid (); |
||
964 | if (g_strcmp0 (initial_response, sid) == 0) |
||
965 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND; |
||
966 | g_free (sid); |
||
967 | #else |
||
968 | #error Please implement for your OS |
||
969 | #endif |
||
970 | } |
||
971 | } |
||
972 | |||
973 | static void |
||
974 | mechanism_server_data_receive (GDBusAuthMechanism *mechanism, |
||
975 | const gchar *data, |
||
976 | gsize data_len) |
||
977 | { |
||
978 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
979 | gchar **tokens; |
||
980 | const gchar *client_challenge; |
||
981 | const gchar *alleged_sha1; |
||
982 | gchar *sha1; |
||
983 | |||
984 | g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism)); |
||
985 | g_return_if_fail (m->priv->is_server && !m->priv->is_client); |
||
986 | g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA); |
||
987 | |||
988 | tokens = NULL; |
||
989 | sha1 = NULL; |
||
990 | |||
991 | tokens = g_strsplit (data, " ", 0); |
||
992 | if (g_strv_length (tokens) != 2) |
||
993 | { |
||
994 | g_warning ("Malformed data '%s'", data); |
||
995 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; |
||
996 | goto out; |
||
997 | } |
||
998 | |||
999 | client_challenge = tokens[0]; |
||
1000 | alleged_sha1 = tokens[1]; |
||
1001 | |||
1002 | sha1 = generate_sha1 (m->priv->server_challenge, client_challenge, m->priv->cookie); |
||
1003 | |||
1004 | if (g_strcmp0 (sha1, alleged_sha1) == 0) |
||
1005 | { |
||
1006 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED; |
||
1007 | } |
||
1008 | else |
||
1009 | { |
||
1010 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; |
||
1011 | } |
||
1012 | |||
1013 | out: |
||
1014 | g_strfreev (tokens); |
||
1015 | g_free (sha1); |
||
1016 | } |
||
1017 | |||
1018 | static gchar * |
||
1019 | mechanism_server_data_send (GDBusAuthMechanism *mechanism, |
||
1020 | gsize *out_data_len) |
||
1021 | { |
||
1022 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1023 | gchar *s; |
||
1024 | gint cookie_id; |
||
1025 | const gchar *cookie_context; |
||
1026 | GError *error; |
||
1027 | |||
1028 | g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL); |
||
1029 | g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL); |
||
1030 | g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL); |
||
1031 | |||
1032 | s = NULL; |
||
1033 | |||
1034 | /* TODO: use GDBusAuthObserver here to get the cookie context to use? */ |
||
1035 | cookie_context = "org_gtk_gdbus_general"; |
||
1036 | |||
1037 | cookie_id = -1; |
||
1038 | error = NULL; |
||
1039 | if (!keyring_generate_entry (cookie_context, |
||
1040 | &cookie_id, |
||
1041 | &m->priv->cookie, |
||
1042 | &error)) |
||
1043 | { |
||
1044 | g_warning ("Error adding entry to keyring: %s", error->message); |
||
1045 | g_error_free (error); |
||
1046 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; |
||
1047 | goto out; |
||
1048 | } |
||
1049 | |||
1050 | m->priv->server_challenge = random_ascii_string (16); |
||
1051 | s = g_strdup_printf ("%s %d %s", |
||
1052 | cookie_context, |
||
1053 | cookie_id, |
||
1054 | m->priv->server_challenge); |
||
1055 | |||
1056 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA; |
||
1057 | |||
1058 | out: |
||
1059 | return s; |
||
1060 | } |
||
1061 | |||
1062 | static gchar * |
||
1063 | mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism) |
||
1064 | { |
||
1065 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1066 | |||
1067 | g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL); |
||
1068 | g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL); |
||
1069 | g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL); |
||
1070 | |||
1071 | /* can never end up here because we are never in the REJECTED state */ |
||
1072 | g_assert_not_reached (); |
||
1073 | |||
1074 | return NULL; |
||
1075 | } |
||
1076 | |||
1077 | static void |
||
1078 | mechanism_server_shutdown (GDBusAuthMechanism *mechanism) |
||
1079 | { |
||
1080 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1081 | |||
1082 | g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism)); |
||
1083 | g_return_if_fail (m->priv->is_server && !m->priv->is_client); |
||
1084 | |||
1085 | m->priv->is_server = FALSE; |
||
1086 | } |
||
1087 | |||
1088 | /* ---------------------------------------------------------------------------------------------------- */ |
||
1089 | |||
1090 | static GDBusAuthMechanismState |
||
1091 | mechanism_client_get_state (GDBusAuthMechanism *mechanism) |
||
1092 | { |
||
1093 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1094 | |||
1095 | g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID); |
||
1096 | g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID); |
||
1097 | |||
1098 | return m->priv->state; |
||
1099 | } |
||
1100 | |||
1101 | static gchar * |
||
1102 | mechanism_client_initiate (GDBusAuthMechanism *mechanism, |
||
1103 | gsize *out_initial_response_len) |
||
1104 | { |
||
1105 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1106 | gchar *initial_response; |
||
1107 | |||
1108 | g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL); |
||
1109 | g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL); |
||
1110 | |||
1111 | m->priv->is_client = TRUE; |
||
1112 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA; |
||
1113 | |||
1114 | *out_initial_response_len = -1; |
||
1115 | |||
1116 | #ifdef G_OS_UNIX |
||
1117 | initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ()); |
||
1118 | #elif defined (G_OS_WIN32) |
||
1119 | initial_response = _g_dbus_win32_get_user_sid (); |
||
1120 | #else |
||
1121 | #error Please implement for your OS |
||
1122 | #endif |
||
1123 | g_assert (initial_response != NULL); |
||
1124 | |||
1125 | return initial_response; |
||
1126 | } |
||
1127 | |||
1128 | static void |
||
1129 | mechanism_client_data_receive (GDBusAuthMechanism *mechanism, |
||
1130 | const gchar *data, |
||
1131 | gsize data_len) |
||
1132 | { |
||
1133 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1134 | gchar **tokens; |
||
1135 | const gchar *cookie_context; |
||
1136 | guint cookie_id; |
||
1137 | const gchar *server_challenge; |
||
1138 | gchar *client_challenge; |
||
1139 | gchar *endp; |
||
1140 | gchar *cookie; |
||
1141 | GError *error; |
||
1142 | gchar *sha1; |
||
1143 | |||
1144 | g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism)); |
||
1145 | g_return_if_fail (m->priv->is_client && !m->priv->is_server); |
||
1146 | g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA); |
||
1147 | |||
1148 | tokens = NULL; |
||
1149 | cookie = NULL; |
||
1150 | client_challenge = NULL; |
||
1151 | |||
1152 | tokens = g_strsplit (data, " ", 0); |
||
1153 | if (g_strv_length (tokens) != 3) |
||
1154 | { |
||
1155 | g_warning ("Malformed data '%s'", data); |
||
1156 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; |
||
1157 | goto out; |
||
1158 | } |
||
1159 | |||
1160 | cookie_context = tokens[0]; |
||
1161 | cookie_id = g_ascii_strtoll (tokens[1], &endp, 10); |
||
1162 | if (*endp != '\0') |
||
1163 | { |
||
1164 | g_warning ("Malformed cookie_id '%s'", tokens[1]); |
||
1165 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; |
||
1166 | goto out; |
||
1167 | } |
||
1168 | server_challenge = tokens[2]; |
||
1169 | |||
1170 | error = NULL; |
||
1171 | cookie = keyring_lookup_entry (cookie_context, cookie_id, &error); |
||
1172 | if (cookie == NULL) |
||
1173 | { |
||
1174 | g_warning ("Problems looking up entry in keyring: %s", error->message); |
||
1175 | g_error_free (error); |
||
1176 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; |
||
1177 | goto out; |
||
1178 | } |
||
1179 | |||
1180 | client_challenge = random_ascii_string (16); |
||
1181 | sha1 = generate_sha1 (server_challenge, client_challenge, cookie); |
||
1182 | m->priv->to_send = g_strdup_printf ("%s %s", client_challenge, sha1); |
||
1183 | g_free (sha1); |
||
1184 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND; |
||
1185 | |||
1186 | out: |
||
1187 | g_strfreev (tokens); |
||
1188 | g_free (cookie); |
||
1189 | g_free (client_challenge); |
||
1190 | } |
||
1191 | |||
1192 | static gchar * |
||
1193 | mechanism_client_data_send (GDBusAuthMechanism *mechanism, |
||
1194 | gsize *out_data_len) |
||
1195 | { |
||
1196 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1197 | |||
1198 | g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL); |
||
1199 | g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL); |
||
1200 | g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL); |
||
1201 | |||
1202 | g_assert (m->priv->to_send != NULL); |
||
1203 | |||
1204 | m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED; |
||
1205 | |||
1206 | return g_strdup (m->priv->to_send); |
||
1207 | } |
||
1208 | |||
1209 | static void |
||
1210 | mechanism_client_shutdown (GDBusAuthMechanism *mechanism) |
||
1211 | { |
||
1212 | GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism); |
||
1213 | |||
1214 | g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism)); |
||
1215 | g_return_if_fail (m->priv->is_client && !m->priv->is_server); |
||
1216 | |||
1217 | m->priv->is_client = FALSE; |
||
1218 | } |
||
1219 | |||
1220 | /* ---------------------------------------------------------------------------------------------------- */ |