Update Friulian translation
[glib.git] / gio / gdbusauthmechanismsha1.c
bloba51430cfaeb61ec161a37b91a2f60f0aa1375d16
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
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.
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.
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/>.
18 * Author: David Zeuthen <davidz@redhat.com>
21 #include "config.h"
23 #include <string.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <sys/types.h>
28 #include <glib/gstdio.h>
30 #ifdef G_OS_UNIX
31 #include <unistd.h>
32 #endif
33 #ifdef G_OS_WIN32
34 #include <io.h>
35 #endif
37 #include "gdbusauthmechanismsha1.h"
38 #include "gcredentials.h"
39 #include "gdbuserror.h"
40 #include "gioenumtypes.h"
41 #include "gioerror.h"
42 #include "gdbusprivate.h"
44 #include "glibintl.h"
46 struct _GDBusAuthMechanismSha1Private
48 gboolean is_client;
49 gboolean is_server;
50 GDBusAuthMechanismState state;
52 /* used on the client side */
53 gchar *to_send;
55 /* used on the server side */
56 gchar *cookie;
57 gchar *server_challenge;
60 static gint mechanism_get_priority (void);
61 static const gchar *mechanism_get_name (void);
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);
93 /* ---------------------------------------------------------------------------------------------------- */
95 G_DEFINE_TYPE_WITH_PRIVATE (GDBusAuthMechanismSha1, _g_dbus_auth_mechanism_sha1, G_TYPE_DBUS_AUTH_MECHANISM)
97 /* ---------------------------------------------------------------------------------------------------- */
99 static void
100 _g_dbus_auth_mechanism_sha1_finalize (GObject *object)
102 GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object);
104 g_free (mechanism->priv->to_send);
106 g_free (mechanism->priv->cookie);
107 g_free (mechanism->priv->server_challenge);
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);
113 static void
114 _g_dbus_auth_mechanism_sha1_class_init (GDBusAuthMechanismSha1Class *klass)
116 GObjectClass *gobject_class;
117 GDBusAuthMechanismClass *mechanism_class;
119 gobject_class = G_OBJECT_CLASS (klass);
120 gobject_class->finalize = _g_dbus_auth_mechanism_sha1_finalize;
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;
141 static void
142 _g_dbus_auth_mechanism_sha1_init (GDBusAuthMechanismSha1 *mechanism)
144 mechanism->priv = _g_dbus_auth_mechanism_sha1_get_instance_private (mechanism);
147 /* ---------------------------------------------------------------------------------------------------- */
149 static gint
150 mechanism_get_priority (void)
152 return 0;
155 static const gchar *
156 mechanism_get_name (void)
158 return "DBUS_COOKIE_SHA1";
161 static gboolean
162 mechanism_is_supported (GDBusAuthMechanism *mechanism)
164 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), FALSE);
165 return TRUE;
168 static gchar *
169 mechanism_encode_data (GDBusAuthMechanism *mechanism,
170 const gchar *data,
171 gsize data_len,
172 gsize *out_data_len)
174 return NULL;
178 static gchar *
179 mechanism_decode_data (GDBusAuthMechanism *mechanism,
180 const gchar *data,
181 gsize data_len,
182 gsize *out_data_len)
184 return NULL;
187 /* ---------------------------------------------------------------------------------------------------- */
189 static gint
190 random_ascii (void)
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;
203 static gchar *
204 random_ascii_string (guint len)
206 GString *challenge;
207 guint n;
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);
215 static gchar *
216 random_blob (guint len)
218 GString *challenge;
219 guint n;
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);
227 /* ---------------------------------------------------------------------------------------------------- */
229 /* ensure keyring dir exists and permissions are correct */
230 static gchar *
231 ensure_keyring_directory (GError **error)
233 gchar *path;
234 const gchar *e;
236 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
238 e = g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR");
239 if (e != NULL)
241 path = g_strdup (e);
243 else
245 path = g_build_filename (g_get_home_dir (),
246 ".dbus-keyrings",
247 NULL);
250 if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
252 if (g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION") == NULL)
254 #ifdef G_OS_UNIX
255 struct stat statbuf;
256 if (stat (path, &statbuf) != 0)
258 int errsv = errno;
259 g_set_error (error,
260 G_IO_ERROR,
261 g_io_error_from_errno (errsv),
262 _("Error when getting information for directory “%s”: %s"),
263 path,
264 g_strerror (errsv));
265 g_free (path);
266 path = NULL;
267 goto out;
269 if ((statbuf.st_mode & 0777) != 0700)
271 g_set_error (error,
272 G_IO_ERROR,
273 G_IO_ERROR_FAILED,
274 _("Permissions on directory “%s” are malformed. Expected mode 0700, got 0%o"),
275 path,
276 statbuf.st_mode & 0777);
277 g_free (path);
278 path = NULL;
279 goto out;
281 #else
282 #ifdef __GNUC__
283 #warning Please implement permission checking on this non-UNIX platform
284 #endif
285 #endif
287 goto out;
290 if (g_mkdir (path, 0700) != 0)
292 int errsv = errno;
293 g_set_error (error,
294 G_IO_ERROR,
295 g_io_error_from_errno (errsv),
296 _("Error creating directory “%s”: %s"),
297 path,
298 g_strerror (errsv));
299 g_free (path);
300 path = NULL;
301 goto out;
304 out:
305 return path;
308 /* ---------------------------------------------------------------------------------------------------- */
310 static void
311 append_nibble (GString *s, gint val)
313 g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val));
316 static gchar *
317 hexencode (const gchar *str,
318 gssize len)
320 guint n;
321 GString *s;
323 if (len == -1)
324 len = strlen (str);
326 s = g_string_new (NULL);
327 for (n = 0; n < len; n++)
329 gint val;
330 gint upper_nibble;
331 gint lower_nibble;
333 val = ((const guchar *) str)[n];
334 upper_nibble = val >> 4;
335 lower_nibble = val & 0x0f;
337 append_nibble (s, upper_nibble);
338 append_nibble (s, lower_nibble);
341 return g_string_free (s, FALSE);
344 /* ---------------------------------------------------------------------------------------------------- */
346 /* looks up an entry in the keyring */
347 static gchar *
348 keyring_lookup_entry (const gchar *cookie_context,
349 gint cookie_id,
350 GError **error)
352 gchar *ret;
353 gchar *keyring_dir;
354 gchar *contents;
355 gchar *path;
356 guint n;
357 gchar **lines;
359 g_return_val_if_fail (cookie_context != NULL, NULL);
360 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
362 ret = NULL;
363 path = NULL;
364 contents = NULL;
365 lines = NULL;
367 keyring_dir = ensure_keyring_directory (error);
368 if (keyring_dir == NULL)
369 goto out;
371 path = g_build_filename (keyring_dir, cookie_context, NULL);
373 if (!g_file_get_contents (path,
374 &contents,
375 NULL,
376 error))
378 g_prefix_error (error,
379 _("Error opening keyring “%s” for reading: "),
380 path);
381 goto out;
383 g_assert (contents != NULL);
385 lines = g_strsplit (contents, "\n", 0);
386 for (n = 0; lines[n] != NULL; n++)
388 const gchar *line = lines[n];
389 gchar **tokens;
390 gchar *endp;
391 gint line_id;
392 guint64 line_when;
394 if (line[0] == '\0')
395 continue;
397 tokens = g_strsplit (line, " ", 0);
398 if (g_strv_length (tokens) != 3)
400 g_set_error (error,
401 G_IO_ERROR,
402 G_IO_ERROR_FAILED,
403 _("Line %d of the keyring at “%s” with content “%s” is malformed"),
404 n + 1,
405 path,
406 line);
407 g_strfreev (tokens);
408 goto out;
411 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
412 if (*endp != '\0')
414 g_set_error (error,
415 G_IO_ERROR,
416 G_IO_ERROR_FAILED,
417 _("First token of line %d of the keyring at “%s” with content “%s” is malformed"),
418 n + 1,
419 path,
420 line);
421 g_strfreev (tokens);
422 goto out;
425 line_when = g_ascii_strtoll (tokens[1], &endp, 10);
426 line_when = line_when; /* To avoid -Wunused-but-set-variable */
427 if (*endp != '\0')
429 g_set_error (error,
430 G_IO_ERROR,
431 G_IO_ERROR_FAILED,
432 _("Second token of line %d of the keyring at “%s” with content “%s” is malformed"),
433 n + 1,
434 path,
435 line);
436 g_strfreev (tokens);
437 goto out;
440 if (line_id == cookie_id)
442 /* YAY, success */
443 ret = tokens[2]; /* steal pointer */
444 tokens[2] = NULL;
445 g_strfreev (tokens);
446 goto out;
449 g_strfreev (tokens);
452 /* BOOH, didn't find the cookie */
453 g_set_error (error,
454 G_IO_ERROR,
455 G_IO_ERROR_FAILED,
456 _("Didn’t find cookie with id %d in the keyring at “%s”"),
457 cookie_id,
458 path);
460 out:
461 g_free (keyring_dir);
462 g_free (path);
463 g_free (contents);
464 g_strfreev (lines);
465 return ret;
468 /* function for logging important events that the system administrator should take notice of */
469 G_GNUC_PRINTF(1, 2)
470 static void
471 _log (const gchar *message,
472 ...)
474 gchar *s;
475 va_list var_args;
477 va_start (var_args, message);
478 s = g_strdup_vprintf (message, var_args);
479 va_end (var_args);
481 /* TODO: might want to send this to syslog instead */
482 g_printerr ("GDBus-DBUS_COOKIE_SHA1: %s\n", s);
483 g_free (s);
486 static gint
487 keyring_acquire_lock (const gchar *path,
488 GError **error)
490 gchar *lock;
491 gint ret;
492 guint num_tries;
493 guint num_create_tries;
494 int errsv;
496 g_return_val_if_fail (path != NULL, FALSE);
497 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
499 ret = -1;
500 lock = g_strdup_printf ("%s.lock", path);
502 /* This is what the D-Bus spec says
504 * Create a lockfile name by appending ".lock" to the name of the
505 * cookie file. The server should attempt to create this file using
506 * O_CREAT | O_EXCL. If file creation fails, the lock
507 * fails. Servers should retry for a reasonable period of time,
508 * then they may choose to delete an existing lock to keep users
509 * from having to manually delete a stale lock. [1]
511 * [1] : Lockfiles are used instead of real file locking fcntl() because
512 * real locking implementations are still flaky on network filesystems
515 num_create_tries = 0;
516 #ifdef EEXISTS
517 again:
518 #endif
519 num_tries = 0;
520 while (g_file_test (lock, G_FILE_TEST_EXISTS))
522 /* sleep 10ms, then try again */
523 g_usleep (1000*10);
524 num_tries++;
525 if (num_tries == 50)
527 /* ok, we slept 50*10ms = 0.5 seconds. Conclude that the lock file must be
528 * stale (nuke the it from orbit)
530 if (g_unlink (lock) != 0)
532 errsv = errno;
533 g_set_error (error,
534 G_IO_ERROR,
535 g_io_error_from_errno (errsv),
536 _("Error deleting stale lock file “%s”: %s"),
537 lock,
538 g_strerror (errsv));
539 goto out;
541 _log ("Deleted stale lock file '%s'", lock);
542 break;
546 ret = g_open (lock, O_CREAT |
547 #ifdef O_EXCL
548 O_EXCL,
549 #else
551 #endif
552 0700);
553 errsv = errno;
554 if (ret == -1)
556 #ifdef EEXISTS
557 /* EEXIST: pathname already exists and O_CREAT and O_EXCL were used. */
558 if (errsv == EEXISTS)
560 num_create_tries++;
561 if (num_create_tries < 5)
562 goto again;
564 #endif
565 num_create_tries = num_create_tries; /* To avoid -Wunused-but-set-variable */
566 g_set_error (error,
567 G_IO_ERROR,
568 g_io_error_from_errno (errsv),
569 _("Error creating lock file “%s”: %s"),
570 lock,
571 g_strerror (errsv));
572 goto out;
575 out:
576 g_free (lock);
577 return ret;
580 static gboolean
581 keyring_release_lock (const gchar *path,
582 gint lock_fd,
583 GError **error)
585 gchar *lock;
586 gboolean ret;
588 g_return_val_if_fail (path != NULL, FALSE);
589 g_return_val_if_fail (lock_fd != -1, FALSE);
590 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
592 ret = FALSE;
593 lock = g_strdup_printf ("%s.lock", path);
594 if (close (lock_fd) != 0)
596 int errsv = errno;
597 g_set_error (error,
598 G_IO_ERROR,
599 g_io_error_from_errno (errsv),
600 _("Error closing (unlinked) lock file “%s”: %s"),
601 lock,
602 g_strerror (errsv));
603 goto out;
605 if (g_unlink (lock) != 0)
607 int errsv = errno;
608 g_set_error (error,
609 G_IO_ERROR,
610 g_io_error_from_errno (errsv),
611 _("Error unlinking lock file “%s”: %s"),
612 lock,
613 g_strerror (errsv));
614 goto out;
617 ret = TRUE;
619 out:
620 g_free (lock);
621 return ret;
625 /* adds an entry to the keyring, taking care of locking and deleting stale/future entries */
626 static gboolean
627 keyring_generate_entry (const gchar *cookie_context,
628 gint *out_id,
629 gchar **out_cookie,
630 GError **error)
632 gboolean ret;
633 gchar *keyring_dir;
634 gchar *path;
635 gchar *contents;
636 GError *local_error;
637 gchar **lines;
638 gint max_line_id;
639 GString *new_contents;
640 guint64 now;
641 gboolean have_id;
642 gint use_id;
643 gchar *use_cookie;
644 gboolean changed_file;
645 gint lock_fd;
647 g_return_val_if_fail (cookie_context != NULL, FALSE);
648 g_return_val_if_fail (out_id != NULL, FALSE);
649 g_return_val_if_fail (out_cookie != NULL, FALSE);
650 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
652 ret = FALSE;
653 path = NULL;
654 contents = NULL;
655 lines = NULL;
656 new_contents = NULL;
657 have_id = FALSE;
658 use_id = 0;
659 use_cookie = NULL;
660 lock_fd = -1;
662 keyring_dir = ensure_keyring_directory (error);
663 if (keyring_dir == NULL)
664 goto out;
666 path = g_build_filename (keyring_dir, cookie_context, NULL);
668 lock_fd = keyring_acquire_lock (path, error);
669 if (lock_fd == -1)
670 goto out;
672 local_error = NULL;
673 contents = NULL;
674 if (!g_file_get_contents (path,
675 &contents,
676 NULL,
677 &local_error))
679 if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT)
681 /* file doesn't have to exist */
682 g_error_free (local_error);
684 else
686 g_propagate_prefixed_error (error,
687 local_error,
688 _("Error opening keyring “%s” for writing: "),
689 path);
690 goto out;
694 new_contents = g_string_new (NULL);
695 now = time (NULL);
696 changed_file = FALSE;
698 max_line_id = 0;
699 if (contents != NULL)
701 guint n;
702 lines = g_strsplit (contents, "\n", 0);
703 for (n = 0; lines[n] != NULL; n++)
705 const gchar *line = lines[n];
706 gchar **tokens;
707 gchar *endp;
708 gint line_id;
709 guint64 line_when;
710 gboolean keep_entry;
712 if (line[0] == '\0')
713 continue;
715 tokens = g_strsplit (line, " ", 0);
716 if (g_strv_length (tokens) != 3)
718 g_set_error (error,
719 G_IO_ERROR,
720 G_IO_ERROR_FAILED,
721 _("Line %d of the keyring at “%s” with content “%s” is malformed"),
722 n + 1,
723 path,
724 line);
725 g_strfreev (tokens);
726 goto out;
729 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
730 if (*endp != '\0')
732 g_set_error (error,
733 G_IO_ERROR,
734 G_IO_ERROR_FAILED,
735 _("First token of line %d of the keyring at “%s” with content “%s” is malformed"),
736 n + 1,
737 path,
738 line);
739 g_strfreev (tokens);
740 goto out;
743 line_when = g_ascii_strtoll (tokens[1], &endp, 10);
744 if (*endp != '\0')
746 g_set_error (error,
747 G_IO_ERROR,
748 G_IO_ERROR_FAILED,
749 _("Second token of line %d of the keyring at “%s” with content “%s” is malformed"),
750 n + 1,
751 path,
752 line);
753 g_strfreev (tokens);
754 goto out;
756 line_when = line_when; /* To avoid -Wunused-but-set-variable */
759 /* D-Bus spec says:
761 * Once the lockfile has been created, the server loads the
762 * cookie file. It should then delete any cookies that are
763 * old (the timeout can be fairly short), or more than a
764 * reasonable time in the future (so that cookies never
765 * accidentally become permanent, if the clock was set far
766 * into the future at some point). If no recent keys remain,
767 * the server may generate a new key.
770 keep_entry = TRUE;
771 if (line_when > now)
773 /* Oddball case: entry is more recent than our current wall-clock time..
774 * This is OK, it means that another server on another machine but with
775 * same $HOME wrote the entry.
777 * So discard the entry if it's more than 1 day in the future ("reasonable
778 * time in the future").
780 if (line_when - now > 24*60*60)
782 keep_entry = FALSE;
783 _log ("Deleted SHA1 cookie from %" G_GUINT64_FORMAT " seconds in the future", line_when - now);
786 else
788 /* Discard entry if it's older than 15 minutes ("can be fairly short") */
789 if (now - line_when > 15*60)
791 keep_entry = FALSE;
795 if (!keep_entry)
797 changed_file = FALSE;
799 else
801 g_string_append_printf (new_contents,
802 "%d %" G_GUINT64_FORMAT " %s\n",
803 line_id,
804 line_when,
805 tokens[2]);
806 max_line_id = MAX (line_id, max_line_id);
807 /* Only reuse entry if not older than 10 minutes.
809 * (We need a bit of grace time compared to 15 minutes above.. otherwise
810 * there's a race where we reuse the 14min59.9 secs old entry and a
811 * split-second later another server purges the now 15 minute old entry.)
813 if (now - line_when < 10 * 60)
815 if (!have_id)
817 use_id = line_id;
818 use_cookie = tokens[2]; /* steal memory */
819 tokens[2] = NULL;
820 have_id = TRUE;
824 g_strfreev (tokens);
826 } /* for each line */
828 ret = TRUE;
830 if (have_id)
832 *out_id = use_id;
833 *out_cookie = use_cookie;
834 use_cookie = NULL;
836 else
838 gchar *raw_cookie;
839 *out_id = max_line_id + 1;
840 raw_cookie = random_blob (32);
841 *out_cookie = hexencode (raw_cookie, 32);
842 g_free (raw_cookie);
844 g_string_append_printf (new_contents,
845 "%d %" G_GUINT64_FORMAT " %s\n",
846 *out_id,
847 (guint64) time (NULL),
848 *out_cookie);
849 changed_file = TRUE;
852 /* and now actually write the cookie file if there are changes (this is atomic) */
853 if (changed_file)
855 if (!g_file_set_contents (path,
856 new_contents->str,
858 error))
860 *out_id = 0;
861 *out_cookie = 0;
862 g_free (*out_cookie);
863 ret = FALSE;
864 goto out;
868 out:
870 if (lock_fd != -1)
872 GError *local_error;
873 local_error = NULL;
874 if (!keyring_release_lock (path, lock_fd, &local_error))
876 if (error != NULL)
878 if (*error == NULL)
880 *error = local_error;
882 else
884 g_prefix_error (error,
885 _("(Additionally, releasing the lock for “%s” also failed: %s) "),
886 path,
887 local_error->message);
890 else
892 g_error_free (local_error);
897 g_free (keyring_dir);
898 g_free (path);
899 g_strfreev (lines);
900 g_free (contents);
901 if (new_contents != NULL)
902 g_string_free (new_contents, TRUE);
903 g_free (use_cookie);
904 return ret;
907 /* ---------------------------------------------------------------------------------------------------- */
909 static gchar *
910 generate_sha1 (const gchar *server_challenge,
911 const gchar *client_challenge,
912 const gchar *cookie)
914 GString *str;
915 gchar *sha1;
917 str = g_string_new (server_challenge);
918 g_string_append_c (str, ':');
919 g_string_append (str, client_challenge);
920 g_string_append_c (str, ':');
921 g_string_append (str, cookie);
922 sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str->str, -1);
923 g_string_free (str, TRUE);
925 return sha1;
928 /* ---------------------------------------------------------------------------------------------------- */
930 static GDBusAuthMechanismState
931 mechanism_server_get_state (GDBusAuthMechanism *mechanism)
933 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
935 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
936 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
938 return m->priv->state;
941 static void
942 mechanism_server_initiate (GDBusAuthMechanism *mechanism,
943 const gchar *initial_response,
944 gsize initial_response_len)
946 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
948 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
949 g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
951 m->priv->is_server = TRUE;
952 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
954 if (initial_response != NULL && strlen (initial_response) > 0)
956 #ifdef G_OS_UNIX
957 gint64 uid;
958 gchar *endp;
960 uid = g_ascii_strtoll (initial_response, &endp, 10);
961 if (*endp == '\0')
963 if (uid == getuid ())
965 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
968 #elif defined(G_OS_WIN32)
969 gchar *sid;
970 sid = _g_dbus_win32_get_user_sid ();
971 if (g_strcmp0 (initial_response, sid) == 0)
972 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
973 g_free (sid);
974 #else
975 #error Please implement for your OS
976 #endif
980 static void
981 mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
982 const gchar *data,
983 gsize data_len)
985 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
986 gchar **tokens;
987 const gchar *client_challenge;
988 const gchar *alleged_sha1;
989 gchar *sha1;
991 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
992 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
993 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
995 tokens = NULL;
996 sha1 = NULL;
998 tokens = g_strsplit (data, " ", 0);
999 if (g_strv_length (tokens) != 2)
1001 g_warning ("Malformed data '%s'", data);
1002 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1003 goto out;
1006 client_challenge = tokens[0];
1007 alleged_sha1 = tokens[1];
1009 sha1 = generate_sha1 (m->priv->server_challenge, client_challenge, m->priv->cookie);
1011 if (g_strcmp0 (sha1, alleged_sha1) == 0)
1013 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1015 else
1017 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1020 out:
1021 g_strfreev (tokens);
1022 g_free (sha1);
1025 static gchar *
1026 mechanism_server_data_send (GDBusAuthMechanism *mechanism,
1027 gsize *out_data_len)
1029 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1030 gchar *s;
1031 gint cookie_id;
1032 const gchar *cookie_context;
1033 GError *error;
1035 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1036 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1037 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1039 s = NULL;
1041 /* TODO: use GDBusAuthObserver here to get the cookie context to use? */
1042 cookie_context = "org_gtk_gdbus_general";
1044 cookie_id = -1;
1045 error = NULL;
1046 if (!keyring_generate_entry (cookie_context,
1047 &cookie_id,
1048 &m->priv->cookie,
1049 &error))
1051 g_warning ("Error adding entry to keyring: %s", error->message);
1052 g_error_free (error);
1053 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1054 goto out;
1057 m->priv->server_challenge = random_ascii_string (16);
1058 s = g_strdup_printf ("%s %d %s",
1059 cookie_context,
1060 cookie_id,
1061 m->priv->server_challenge);
1063 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1065 out:
1066 return s;
1069 static gchar *
1070 mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
1072 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1074 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1075 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1076 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
1078 /* can never end up here because we are never in the REJECTED state */
1079 g_assert_not_reached ();
1081 return NULL;
1084 static void
1085 mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
1087 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1089 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1090 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
1092 m->priv->is_server = FALSE;
1095 /* ---------------------------------------------------------------------------------------------------- */
1097 static GDBusAuthMechanismState
1098 mechanism_client_get_state (GDBusAuthMechanism *mechanism)
1100 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1102 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1103 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1105 return m->priv->state;
1108 static gchar *
1109 mechanism_client_initiate (GDBusAuthMechanism *mechanism,
1110 gsize *out_initial_response_len)
1112 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1113 gchar *initial_response;
1115 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1116 g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
1118 m->priv->is_client = TRUE;
1119 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1121 *out_initial_response_len = -1;
1123 #ifdef G_OS_UNIX
1124 initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ());
1125 #elif defined (G_OS_WIN32)
1126 initial_response = _g_dbus_win32_get_user_sid ();
1127 #else
1128 #error Please implement for your OS
1129 #endif
1130 g_assert (initial_response != NULL);
1132 return initial_response;
1135 static void
1136 mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
1137 const gchar *data,
1138 gsize data_len)
1140 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1141 gchar **tokens;
1142 const gchar *cookie_context;
1143 guint cookie_id;
1144 const gchar *server_challenge;
1145 gchar *client_challenge;
1146 gchar *endp;
1147 gchar *cookie;
1148 GError *error;
1149 gchar *sha1;
1151 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1152 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1153 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
1155 tokens = NULL;
1156 cookie = NULL;
1157 client_challenge = NULL;
1159 tokens = g_strsplit (data, " ", 0);
1160 if (g_strv_length (tokens) != 3)
1162 g_warning ("Malformed data '%s'", data);
1163 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1164 goto out;
1167 cookie_context = tokens[0];
1168 cookie_id = g_ascii_strtoll (tokens[1], &endp, 10);
1169 if (*endp != '\0')
1171 g_warning ("Malformed cookie_id '%s'", tokens[1]);
1172 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1173 goto out;
1175 server_challenge = tokens[2];
1177 error = NULL;
1178 cookie = keyring_lookup_entry (cookie_context, cookie_id, &error);
1179 if (cookie == NULL)
1181 g_warning ("Problems looking up entry in keyring: %s", error->message);
1182 g_error_free (error);
1183 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1184 goto out;
1187 client_challenge = random_ascii_string (16);
1188 sha1 = generate_sha1 (server_challenge, client_challenge, cookie);
1189 m->priv->to_send = g_strdup_printf ("%s %s", client_challenge, sha1);
1190 g_free (sha1);
1191 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
1193 out:
1194 g_strfreev (tokens);
1195 g_free (cookie);
1196 g_free (client_challenge);
1199 static gchar *
1200 mechanism_client_data_send (GDBusAuthMechanism *mechanism,
1201 gsize *out_data_len)
1203 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1205 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1206 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
1207 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1209 g_assert (m->priv->to_send != NULL);
1211 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1213 return g_strdup (m->priv->to_send);
1216 static void
1217 mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
1219 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1221 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1222 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1224 m->priv->is_client = FALSE;
1227 /* ---------------------------------------------------------------------------------------------------- */